﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyVoteMVC.Data.Repositories;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data;
using System.Data.Objects;
using MyVoteMVC.Common;

namespace MyVoteMVC.Data
{
    public class VoteDBUnitOfWork : IUnitOfWork
    {
        public VoteDBContext _dbContext = new VoteDBContext();
        private DbTransaction _transaction;

        public bool IsInTransaction
        {
            get { return _transaction != null; }
        }

        private void OpenConnection()
        {
            if (((IObjectContextAdapter)_dbContext).ObjectContext.Connection.State != ConnectionState.Open)
            {
                ((IObjectContextAdapter)_dbContext).ObjectContext.Connection.Open();
            }
        }

        private void ReleaseCurrentTransaction()
        {
            if (_transaction != null)
            {
                _transaction.Dispose();
                _transaction = null;
            }
        }

        #region IUnitOfWork Members

        public void BeginTransaction()
        {
            BeginTransaction(IsolationLevel.ReadCommitted);
        }

        public void BeginTransaction(IsolationLevel isolationLevel)
        {
            if (_transaction != null)
            {
                throw new ApplicationException("已存在事务实例,启动新事务之前请先回滚Rollback或者提交当前事务CommitTransaction");
            }
          
            OpenConnection();
            _transaction = ((IObjectContextAdapter)_dbContext).ObjectContext.Connection.BeginTransaction(isolationLevel);
        }

        public void CommitTransaction()
        {
            if (_transaction == null)
            {
                throw new ApplicationException("不存在事务");
            }

            try
            {
                ((IObjectContextAdapter)_dbContext).ObjectContext.SaveChanges();
                _transaction.Commit();
            }
            catch (UpdateException ex)
            {
                _transaction.Rollback();
                throw ex;
            }
            catch
            {
                _transaction.Rollback();
                throw;
               
            }
            finally
            {
                ReleaseCurrentTransaction();
            }
        }

        public void Commit()
        {
            if (IsInTransaction)
            {
                throw new ApplicationException("有事务在运行，请调用 BeginTransaction ");
            }
            ((IObjectContextAdapter)_dbContext).ObjectContext.SaveChanges();
        }

        public void Commit(SaveOptions saveOptions)
        {
            if (IsInTransaction)
            {
                throw new ApplicationException("有事务在运行，请调用 CommitTransaction ");
            }

            ((IObjectContextAdapter)_dbContext).ObjectContext.SaveChanges(saveOptions);
        }

        public void Rollback()
        {
            _transaction.Rollback();
        }

        public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
        {
            Repository<TEntity> repository = Factory.GetInstance<IRepository<TEntity>>(null) as Repository<TEntity>;
            repository.ctx = this._dbContext;
            return repository;
        }

        public IAdminRepository<TEntity> GetAdminRepository<TEntity>() where TEntity : class
        {
            AdminRepository<TEntity> repository = Factory.GetInstance<IAdminRepository<TEntity>>(null) as AdminRepository<TEntity>;
            repository.ctx = this._dbContext;
            return repository;
        }

        #endregion

        #region IDisposable Members

        private bool m_disposed;

        protected virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                if (disposing)
                {
                    if (this.IsInTransaction)
                        _transaction.Dispose();
                    _dbContext.Dispose();
                }

                // Release unmanaged resources

                m_disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~VoteDBUnitOfWork()
        {
            Dispose(false);
        }

        #endregion
    }
}
